#ifndef INC_IMAGEBUFFER_H
#define INC_IMAGEBUFFER_H

#include <malloc.h>		// Memory allocation	
#include <string.h>		// needed for memcpy
#include <exception>		// Basic exceptions
#include <stdexcept>		// logic_error class header
#include "BaseTypes.h"

/*********************************************/
template<typename T>
class ImageBuffer
{
protected:
	// Data
	T		**data;
	uint32		width, height;
	
public:
	// Methods
	void setPixel( const uint32&, const uint32&, const T& value);
	inline T& getPixel( const uint32&, const uint32& ) const;
	uint32 getHeight();
	uint32 getWidth();
	void clear( const T& value );
	
	// Construction / Destruction
	ImageBuffer( const uint32& width, const uint32& height );		// Constructor
	ImageBuffer( const ImageBuffer& );					// Copy Constructor
	void operator=( const ImageBuffer& );					// Assignment operator
	~ImageBuffer();								// Destructor
};
/*********************************************/
template<typename T>
inline uint32 ImageBuffer<T>::getHeight()
{
	return( height );
}
/*********************************************/
template<typename T>
inline uint32 ImageBuffer<T>::getWidth()
{
	return( width );
}
/*********************************************/
template<typename T>
inline T& ImageBuffer<T>::getPixel( const uint32& x, const uint32& y ) const
{
	return( data[x][y] );
}
/*********************************************/
template<typename T>
void ImageBuffer<T>::setPixel( const uint32& x, const uint32& y, const T& value )
{
	data[x][y] = value;
}
/*********************************************/
template<typename T>
void ImageBuffer<T>::clear( const T& value )
{
	for ( uint32 y = 0; y<height; y++ ) {
		data[0][y] = value;
	}

	for ( uint32 x = 1; x<width; x++ ) {
		memcpy(data[x], data[0], sizeof(T)*height);
	}
}
/*********************************************/
template<typename T>
ImageBuffer<T>::ImageBuffer( const uint32& width, const uint32& height )
{
	if (( width < 1 ) || ( height < 1 )) {
		throw( std::logic_error("Negative or 0 resolution parameter!"));
	}
	
	this->width = width;
	this->height = height;
	
	data = (T**)malloc(sizeof(T*)*width);
	for ( uint32 i = 0; i<width; i++ ) {
		data[i] = (T*)malloc(sizeof(T)*height);
	}
}
/*********************************************/
template<typename T>
ImageBuffer<T>::ImageBuffer( const ImageBuffer& imgBuffer )
{
	width = imgBuffer.width;
	height = imgBuffer.height;

	data = (T**)malloc(sizeof(T)*width);
	for ( uint32 i = 0; i<width; i++ ) {
		data[i] = (T*)malloc(sizeof(T)*height);
		memcpy( data[i], imgBuffer.data[i], sizeof(T)*height );
	}
}
/*********************************************/
template<typename T>
void ImageBuffer<T>::operator=( const ImageBuffer& imgBuffer )
{
	width = imgBuffer.width;
	height = imgBuffer.height;

	data = (T**)malloc(sizeof(T)*width);
	for ( uint32 i = 0; i<width; i++ ) {
		data[i] = (T*)malloc(sizeof(T)*height);
		memcpy( data[i], imgBuffer.data[i], sizeof(T)*height );
	}
}
/*********************************************/
template<typename T>
ImageBuffer<T>::~ImageBuffer()
{
	if ( data != 0 ) {
		for (uint32 i = 0; i<width; i++) {
			free( data[i] );
		}
	}
	free( data );
}
/*********************************************/
#endif // INC_IMAGEBUFFER_H